package cn.bird.storm.validated.paramcheck;

import cn.bird.storm.validated.paramcheck.tool.CheckNode;
import cn.bird.storm.validated.paramcheck.tool.CollCheckCondition;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.AnnotatedElementUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * @version 1.0
 * 参数校验工具
 */
@Slf4j
public class ParamCheckComponent {

    public static ThreadLocal<CheckNode> CHECK_NODE = new ThreadLocal<>();
    public static ThreadLocal<Map<String, Predicate<Object>>> CUSTOMIZE_MAP = new ThreadLocal<>();


    /**
     * 直接用该方法，进行参数校验
     */
    public static void toCheck(Function<ParameterCheckBuilder, ParameterCheckBuilder> checkApply) {
        try {
            //设置当前checkNode
            //一个线程不可能同时进行多个校验，多个线程这里的checkNode不是同一个
            ParameterCheckBuilder parameterCheckBuilder = new ParameterCheckBuilder();
            setCheckNode(
                    CheckNode.builder()
                            .modelMap(new HashMap<>())
                            .parameterCheckBuilder(parameterCheckBuilder)
                            .build()
            );
            //执行校验
            checkApply.apply(parameterCheckBuilder)
                    .check();
        } finally {
            //清理当前checkNode
            log.debug("清理校验数据");
            removeCheckNode();
        }
    }

    public static void check(Object object) {
        check(object, "");
    }
    /**
     * 进行校验
     */
    public static void check(Object object, String group) {
        try {
            if (Objects.isNull(object)) {
                return;
            }
            //一些类型的，不做校验
            if (object instanceof Collection<?>
                    || ObjectUtil.isBasicType(object)
                    || object instanceof String) {
                return;
            }
            //准备
            prepare();
            //组装
            buildUp(object, group);
            //校验
            doCheck();
        } finally {
            //清理当前checkNode
            log.debug("清理校验数据");
            removeCheckNode();
            removeCustomizeMap();
        }
    }
    /**
     * 准备 checkNode
     */
    protected static void prepare() {
        //设置当前checkNode
        //一个线程不可能同时进行多个校验，多个线程这里的checkNode不是同一个
        ParameterCheckBuilder parameterCheckBuilder = new ParameterCheckBuilder();
        setCheckNode(
                CheckNode.builder()
                        .modelMap(new HashMap<>())
                        .parameterCheckBuilder(parameterCheckBuilder)
                        .build()
        );
    }

    /**
     * 准备 checkNode
     */
    protected static void doCheck() {
        getCheckNode().getParameterCheckBuilder().check();
    }

    /**
     * 组装校验内容
     */
    protected static void buildUp(Object object, String group) {
        Field[] fields = ReflectUtil.getFields(object.getClass());
        for (Field field : fields) {
            Set<CheckAnnotation> allMergedAnnotations = AnnotatedElementUtils.findAllMergedAnnotations(field, CheckAnnotation.class);
            //如果没有这个注解，直接跳过
            if (CollUtil.isEmpty(allMergedAnnotations)) {
                continue;
            }
            for (CheckAnnotation mergedAnnotation : allMergedAnnotations) {
                String[] organizes = mergedAnnotation.organizes();
                //1、指定的组是空的
                //2、组不是空的，是否匹配当前指定的组
                if (ArrayUtil.isEmpty(organizes)
                        || (ArrayUtil.isNotEmpty(organizes) && ArrayUtil.contains(organizes, group))) {
                    CollCheckCondition condition = CollCheckCondition.fromBy(mergedAnnotation, object, field);
                    Method method = ReflectUtil.getMethodByName(AnnotationSupportUtil.class, mergedAnnotation.checkType().getMethod());
                    if (Objects.nonNull(method)) {
                        ReflectUtil.invokeStatic(method, condition);
                    }
                }
            }
        }
    }

    /**
     * 组装一个字段
     */
    protected static void buildOne(Object obj, String group, CheckAnnotation checkAnnotation) {
        String[] organizes = checkAnnotation.organizes();
        if (ArrayUtil.isEmpty(organizes)
                || (ArrayUtil.isNotEmpty(organizes) && ArrayUtil.contains(organizes, group))) {
            CollCheckCondition condition = CollCheckCondition.fromByOne(checkAnnotation, obj);
            Method method = ReflectUtil.getMethodByName(AnnotationSupportUtil.class, checkAnnotation.checkType().getMethod());
            if (Objects.nonNull(method)) {
                ReflectUtil.invokeStatic(method, condition);
            }
        }
    }

    /**
     * 自定义校验使用
     * @param key 自定义校验的key
     * @param predicate 自定义校验的方法 true表示校验通过，false表示校验不通过，抛出异常
     */
    public static void customizeTest(String key, Predicate<Object> predicate) {
        Map<String, Predicate<Object>> map = CUSTOMIZE_MAP.get();
        if (Objects.isNull(map)) {
            map = new HashMap<>();
            CUSTOMIZE_MAP.set(map);
        }
        map.put(key, predicate);
    }

    /**
     * 获取当前校验CheckNode
     */
    protected static CheckNode getCheckNode(){
        return CHECK_NODE.get();
    }
    /**
     * 设置当前CheckNode
     */
    protected static void setCheckNode(CheckNode checkNode) {
        CHECK_NODE.set(checkNode);
    }
    /**
     * 清空当前CheckNode
     */
    protected static void removeCheckNode(){
        CHECK_NODE.remove();
    }
    //清空当前自定义校验
    protected static void removeCustomizeMap(){
        CUSTOMIZE_MAP.remove();
    }

}
